/*
 * OpenOfficeHelper.java
 *
 */

package pl.edu.pw.mini.adapter;

import com.sun.star.comp.helper.BootstrapException;
import com.sun.star.frame.XModel;
import com.sun.star.presentation.XPresentationPage;
import com.sun.star.sheet.XSpreadsheetDocument;
import com.sun.star.presentation.XPresentation;
import com.sun.star.text.XTextDocument;
import com.sun.star.lang.XComponent;
import com.sun.star.lang.XMultiComponentFactory;
import com.sun.star.uno.XComponentContext;
import com.sun.star.uno.UnoRuntime;
import com.sun.star.frame.XStorable;
import com.sun.star.beans.PropertyValue;
import com.sun.star.frame.XDesktop;
import com.sun.star.xml.dom.XDocument;
import java.io.File;
import pl.edu.pw.mini.adapter.documents.Document;
import pl.edu.pw.mini.state.StateManager;
import java.net.MalformedURLException;
import java.net.URISyntaxException;

import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import pl.edu.pw.mini.adapter.documents.OpenOfficeDocument;
import pl.edu.pw.mini.adapter.documents.OpenOfficePresentation;
import pl.edu.pw.mini.adapter.documents.OpenOfficeTextDocument;
import pl.edu.pw.mini.adapter.documents.OpenOfficeWorkbook;
import pl.edu.pw.mini.exceptions.InternalException;
import pl.edu.pw.mini.exceptions.OpenOfficeException;
import pl.edu.pw.mini.oo.OOInputStream;
import pl.edu.pw.mini.state.StateManager;

/**
 *
 * @author cdendek
 */

public class OpenOfficeAdapter {
    public enum ExportType{XLS,CSV,ODS,DOC,ODT,ODP};
    public final static String XLS_EXPORT = "MS Excel 97";
    public final static String CSV_EXPORT = "Text - txt - csv (StarCalc)";
    public final static String ODS_EXPORT = "";
    public final static String ODT_EXPORT = "";
    public final static String ODP_EXPORT = "";
    public final static String DOC_EXPORT = "MS Word 97";
    /** Creates a new instance of OpenOfficeHelper */
    protected OpenOfficeAdapter() {
    }
    
    protected static final OpenOfficeAdapter openOfficeAdapter=new OpenOfficeAdapter();
    
    public static OpenOfficeAdapter getInstance(){
        return openOfficeAdapter;
    }
    
    interface DocumentExporter{
        String getOpenOfficeExportStr();
        String getExtension();
        ExportType getExporter();
    }
    
    protected Set<DocumentExporter> docExportSet= new HashSet<DocumentExporter>();
    
    {
        docExportSet.add(new DocumentExporter(){
            public String getOpenOfficeExportStr() {
                return XLS_EXPORT;
            }
            
            public String getExtension() {
                return ".xls";
            }
            
            public OpenOfficeAdapter.ExportType getExporter() {
                return ExportType.XLS;
            }
        });
        docExportSet.add(new DocumentExporter(){
            public String getOpenOfficeExportStr() {
                return CSV_EXPORT;
            }
            
            public String getExtension() {
                return ".csv";
            }
            
            public OpenOfficeAdapter.ExportType getExporter() {
                return ExportType.CSV;
            }
        });
        docExportSet.add(new DocumentExporter(){
            public String getOpenOfficeExportStr() {
                return ODS_EXPORT;
            }
            
            public String getExtension() {
                return ".ods";
            }
            
            public OpenOfficeAdapter.ExportType getExporter() {
                return ExportType.ODS;
            }
        });
        docExportSet.add(new DocumentExporter(){
            public String getOpenOfficeExportStr() {
                return DOC_EXPORT;
            }
            
            public String getExtension() {
                return ".doc";
            }
            
            public OpenOfficeAdapter.ExportType getExporter() {
                return ExportType.DOC;
            }
        });
         docExportSet.add(new DocumentExporter(){
            public String getOpenOfficeExportStr() {
                return ODT_EXPORT;
            }
            
            public String getExtension() {
                return ".odt";
            }
            
            public OpenOfficeAdapter.ExportType getExporter() {
                return ExportType.ODT;
            }
        });
         docExportSet.add(new DocumentExporter(){
            public String getOpenOfficeExportStr() {
                return ODP_EXPORT;
            }
            
            public String getExtension() {
                return ".odp";
            }
            
            public OpenOfficeAdapter.ExportType getExporter() {
                return ExportType.ODP;
            }
        });
    }
    
    protected Map<OpenOfficeAdapter.ExportType,DocumentExporter> docExportMap=new HashMap<OpenOfficeAdapter.ExportType,DocumentExporter>();
    
    {
        for(DocumentExporter dExp:docExportSet){
            docExportMap.put(dExp.getExporter(),dExp);
        }
    }
    
    public static com.sun.star.lang.XComponent showDocument(String title, OOInputStream content) throws InternalException {
        try {
            XComponentContext xRemoteContext = com.sun.star.comp.helper.Bootstrap.bootstrap();
            com.sun.star.lang.XMultiComponentFactory xRemoteServiceManager = xRemoteContext.getServiceManager();
            Object desktop = xRemoteServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xRemoteContext);
            com.sun.star.frame.XComponentLoader xComponentLoader = (com.sun.star.frame.XComponentLoader)com.sun.star.uno.UnoRuntime.queryInterface(com.sun.star.frame.XComponentLoader.class, desktop);
            
            com.sun.star.beans.PropertyValue[] loadProps = new   com.sun.star.beans.PropertyValue[3];
            loadProps[0] = new com.sun.star.beans.PropertyValue();
            loadProps[0].Name = "Hidden";
            loadProps[0].Value = Boolean.FALSE;
            loadProps[1] = new com.sun.star.beans.PropertyValue();
            loadProps[1].Name ="InputStream";
            loadProps[1].Value = content;
            loadProps[2] = new com.sun.star.beans.PropertyValue();
            loadProps[2].Name ="DocumentTitle";
            loadProps[2].Value = title;
            
            com.sun.star.lang.XComponent xDocComponent = xComponentLoader.loadComponentFromURL("private:stream", "_default", 0,  loadProps );
            if (xDocComponent==null){
                throw new InternalException("Failed opening document");
            }
            return xDocComponent;
        } catch (InternalException ex) {
            throw ex;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new InternalException(ex);
        }
    }
    
    public static com.sun.star.lang.XComponent showDocument(URL url) throws InternalException {
        try {
            XComponentContext xRemoteContext = com.sun.star.comp.helper.Bootstrap.bootstrap();
            com.sun.star.lang.XMultiComponentFactory xRemoteServiceManager = xRemoteContext.getServiceManager();
            Object desktop = xRemoteServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xRemoteContext);
            com.sun.star.frame.XComponentLoader xComponentLoader = (com.sun.star.frame.XComponentLoader)com.sun.star.uno.UnoRuntime.queryInterface(com.sun.star.frame.XComponentLoader.class, desktop);
            
            com.sun.star.beans.PropertyValue[] loadProps = new   com.sun.star.beans.PropertyValue[1];
            loadProps[0] = new com.sun.star.beans.PropertyValue();
            loadProps[0].Name = "Hidden";
            loadProps[0].Value = Boolean.FALSE;
            
            com.sun.star.lang.XComponent xDocComponent = xComponentLoader.loadComponentFromURL(url.toString(), "_default", 0,  loadProps );
            if (xDocComponent==null){
                throw new InternalException("Failed opening document");
            }
            return xDocComponent;
        } catch (InternalException ex) {
            throw ex;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw new InternalException(ex);
        }
    }
    
    public static void storeDocumentToStateManager(com.sun.star.lang.XComponent component,Document doc){
        StateManager.storeCurrentDocument(component,doc);
    }
    public static XComponent getCurrentComponent() throws BootstrapException, com.sun.star.uno.Exception{
        XComponentContext xRemoteContext = com.sun.star.comp.helper.Bootstrap.bootstrap();
        XMultiComponentFactory xRemoteServiceManager = xRemoteContext.getServiceManager();
        Object desktop = xRemoteServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", xRemoteContext);
        XDesktop xDesktop = (XDesktop)UnoRuntime.queryInterface(XDesktop.class, desktop);
        XComponent currentComponent = xDesktop.getCurrentComponent();
        return currentComponent;
    }
    
    private static XComponentContext getCurrentComponentContext() throws BootstrapException{
        XComponentContext xRemoteContext = com.sun.star.comp.helper.Bootstrap.bootstrap();
        return xRemoteContext;
    }
    
    private static XSpreadsheetDocument getCurrentSpreadsheet() throws BootstrapException, com.sun.star.uno.Exception {
        XComponent currentComponent = getCurrentComponent();
        XSpreadsheetDocument currentSpreadSheet= (XSpreadsheetDocument)UnoRuntime.queryInterface(XSpreadsheetDocument.class, currentComponent);
        return currentSpreadSheet;
    }
   private static XTextDocument getCurrentTextDocument()throws BootstrapException, com.sun.star.uno.Exception{
        XComponent currentComponent = getCurrentComponent();
        XTextDocument currentText=(XTextDocument)UnoRuntime.queryInterface(XTextDocument.class,currentComponent);
        return currentText;
   }
    private static XPresentationPage getCurrentPresentation()throws BootstrapException, com.sun.star.uno.Exception{
        XComponent currentComponent = getCurrentComponent();
        XPresentationPage currentPresentation=(XPresentationPage)UnoRuntime.queryInterface(XPresentationPage.class,currentComponent);
        return currentPresentation;
   }
    public static XDocument getCurrentDocument() throws BootstrapException, com.sun.star.uno.Exception {

        XComponent currentComponent = getCurrentComponent();
        XDocument xDocument= (XDocument)UnoRuntime.queryInterface(XDocument.class, currentComponent);
        return xDocument;
    }
    
    public static void saveDocument(OpenOfficeDocument owbk,File file) throws InternalException{
        try{
            XStorable storableCurrentComponent = (XStorable)UnoRuntime.queryInterface(XStorable.class,owbk.getDocument());
            PropertyValue[] storeProps = new PropertyValue[0];
            
            URL before = file.toURL();
            String myUNOFileURL =  com.sun.star.uri.ExternalUriReferenceTranslator.create(getCurrentComponentContext()).translateToInternal(before.toExternalForm());
            
            storableCurrentComponent.storeToURL(myUNOFileURL,storeProps);
        } catch(Exception ex){
            throw new InternalException(ex);
        }
    }
    public static void exportDocument(OpenOfficeDocument owbk,File file,ExportType exportType)  throws InternalException,OpenOfficeException{
        try {
            XStorable storableCurrentComponent = (XStorable)UnoRuntime.queryInterface(XStorable.class,owbk.getDocument());
            PropertyValue[] storeProps = new PropertyValue[2];
            storeProps[0]= new PropertyValue();
            storeProps[0].Name = "FilterName";
            storeProps[0].Value = getInstance().docExportMap.get(exportType).getOpenOfficeExportStr();
            storeProps[1]= new PropertyValue();
            storeProps[1].Name = "DocumentTitle";
            storeProps[1].Value = owbk.getTitle();
            URL before = file.toURL();
            String myUNOFileURL =  com.sun.star.uri.ExternalUriReferenceTranslator.create(getCurrentComponentContext()).translateToInternal(before.toExternalForm());
            storableCurrentComponent.storeToURL(myUNOFileURL,storeProps);
            
        } catch (BootstrapException ex) {
            throw new OpenOfficeException(ex);
        } catch (Exception ex) {
            throw new InternalException(ex);
        }
    }
    public static File saveSheetInTempFile(ExportType exportType) throws OpenOfficeException,InternalException{
        return saveDocumentInTempFile(getCurrentWorkbook(),exportType);
    }
    public static File saveDocumentInNamedTempFile(OpenOfficeDocument owbk,ExportType exportType,String title)throws OpenOfficeException, InternalException{
          try{
            DocumentExporter exp=getInstance().docExportMap.get(exportType);
            String temp = System.getProperty("java.io.tmpdir");
            File tmpFile= new File(temp+title+exp.getExtension());
            exportDocument(owbk,tmpFile,exp.getExporter());
            return tmpFile;
            
        }catch(InternalException ex){
            throw ex;
        } catch(Exception ex){
            throw new InternalException(ex);
        }
    }
    public static File saveDocumentInTempFile(OpenOfficeDocument owbk,ExportType exportType) throws OpenOfficeException, InternalException{
        try{
            DocumentExporter exp=getInstance().docExportMap.get(exportType);
            File tmpFile=File.createTempFile("oodoc",exp.getExtension());
            exportDocument(owbk,tmpFile,exp.getExporter());
            return tmpFile;
            
        }catch(InternalException ex){
            throw ex;
        } catch(Exception ex){
            throw new InternalException(ex);
        }
    }
    
    public static File getCurrentWorkbookFile() throws InternalException {
        XModel xDoc = (XModel) UnoRuntime.queryInterface(
                XModel.class, StateManager.getHost().getFrame().getController().getModel());
        try {
            String str=xDoc.getURL();
            if (str==null || "".equals(str)){
                return null;
            }
            return new  File(new URL(str).toURI());
        } catch (MalformedURLException ex) {
            throw new InternalException(ex);
        } catch (URISyntaxException ex) {
            throw new InternalException(ex);
        }
    }
    
    public static OpenOfficeWorkbook getCurrentWorkbook() throws OpenOfficeException{
        try{
            return new OpenOfficeWorkbook(getCurrentSpreadsheet());
        } catch(BootstrapException ex){
            throw new OpenOfficeException(ex);
        } catch(com.sun.star.uno.Exception ex){
            throw new OpenOfficeException(ex);
        }
    }
 public static OpenOfficeTextDocument getCurrentOpenOfficeTextDocument() throws OpenOfficeException{
      try{
            return new OpenOfficeTextDocument(getCurrentTextDocument());
        } catch(BootstrapException ex){
            throw new OpenOfficeException(ex);
        } catch(com.sun.star.uno.Exception ex){
            throw new OpenOfficeException(ex);
        }
 }
 public static OpenOfficePresentation getCurrentOpenOfficePresentation() throws OpenOfficeException{
      try{
            return new OpenOfficePresentation(getCurrentPresentation());
        } catch(BootstrapException ex){
            throw new OpenOfficeException(ex);
        } catch(com.sun.star.uno.Exception ex){
            throw new OpenOfficeException(ex);
        }
 }    
 public static OpenOfficeDocument getCurrentOpenOfficeDocument() throws OpenOfficeException {
      try{
            return new OpenOfficeDocument(getCurrentComponent());
        } catch(BootstrapException ex){
            throw new OpenOfficeException(ex);
        } catch(com.sun.star.uno.Exception ex){
            throw new OpenOfficeException(ex);
        }
 }       
}
